package com.andy.android.usbmanager;

import static com.andy.android.usbmanager.USBReceiver.ACTION_USB_PERMISSION;

import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.hardware.usb.UsbConstants;
import android.hardware.usb.UsbDevice;
import android.hardware.usb.UsbDeviceConnection;
import android.hardware.usb.UsbEndpoint;
import android.hardware.usb.UsbInterface;
import android.hardware.usb.UsbManager;

import androidx.annotation.NonNull;

import com.andy.android.usbmanager.data.GNRMC;
import com.andy.android.usbmanager.data.GNRMCObservable;
import com.andy.android.usbmanager.log.LogCall;

import java.util.Arrays;
import java.util.HashMap;

public enum USBMan {
    INSTANCE;
    private UsbManager usbManager;
    private UsbDevice usbDevice;
    private UsbInterface usbInterface;
    private UsbDeviceConnection deviceConnection;
    private UsbEndpoint usbEpIn;  //代表一个接口的某个节点的类:读数据节点
    private UsbEndpoint usbEpOut;  //代表一个接口的某个节点的类:写数据节点

    private static final byte[] outLock = new byte[0];
    private static final byte[] readLock = new byte[0];
    private boolean isReading;
    private final Runnable readRunnable = new Runnable() {
        @Override
        public void run() {
            while (isReading) {
                try {
                    byte[] recvbytes = new byte[usbEpIn.getMaxPacketSize()];
                    int recv_result = deviceConnection.bulkTransfer(usbEpIn, recvbytes, recvbytes.length, 1000);
                    byte[] tempReadData = null;
                    if (recv_result > 0) {
                        tempReadData = Arrays.copyOf(recvbytes, recv_result);
                    }
                    final byte[] readData = tempReadData;
                    String s = Util.convertHexToString(Util.byte2hex(readData));
                    if (s.contains("GNRMC")) {
                        String[] result = s.split(",");
                        LogCall.d("result count : " + result.length);
                        LogCall.d(s);
                        if (result.length >= 10) {
                            StringBuilder builder = new StringBuilder();
                            builder.append("协议").append(":").append(result[0]).append("\n");
                            builder.append("UTC时间").append(":").append(result[1]).append("\n");
                            builder.append("状态").append(":").append(result[2]).append("\n");
                            builder.append("纬度").append(":").append(result[3]).append("\n");
//                            builder.append("N/S 指示").append(":").append(result[4]).append("\n");
                            builder.append("经度").append(":").append(result[5]).append("\n");
//                            builder.append("E/W 指示").append(":").append(result[6]).append("\n");
//                            builder.append("对地速度").append(":").append(result[7]).append("\n");
//                            builder.append("方位角").append(":").append(result[8]).append("\n");
                            builder.append("日期").append(":").append(result[9]).append("\n");
//                            builder.append("磁偏角").append(":").append(result[10]).append("\n");
//                            builder.append("磁偏角方向").append(":").append(result[11]).append("\n");
//                            builder.append("模式指示").append(":").append(result[12]).append("\n");
//                            builder.append("校验和").append(":").append(result[13]).append("\n");

                            LogCall.d(builder.toString());

                            GNRMC gnrmc  = new GNRMC();
                            gnrmc.setProtocol(result[0]);
                            gnrmc.setUTC(result[1]);
                            gnrmc.setStatus(result[2]);
                            gnrmc.setLatitude(result[3]);
                            gnrmc.setNS(result[4]);
                            gnrmc.setLongitude(result[5]);
                            gnrmc.setEW(result[6]);
                            gnrmc.setSpeed(result[7]);
                            gnrmc.setAngel(result[8]);
                            gnrmc.setDate(result[9]);
//                            gnrmc.setMagneticDeclination(result[10]);
//                            gnrmc.setMagneticDeclinationAngel(result[11]);
//                            gnrmc.setMode(result[12]);
//                            gnrmc.setCheck(result[13]);

                            GNRMCObservable.INSTANCE.onGNRMCChange(gnrmc);
                        }

                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    };

    public void initUsbDevice(Context context) {
        LogCall.d("开始初始化");
        usbManager = (UsbManager) context.getSystemService(Context.USB_SERVICE);
        if (usbManager == null) {
            LogCall.d("该设备不支持读取USB外设");
            return;
        }

        HashMap<String, UsbDevice> deviceList = usbManager.getDeviceList();
        if (!deviceList.isEmpty()) {
            for (UsbDevice device : deviceList.values()) {
                String deviceName = device.getDeviceName();
                int VID = device.getVendorId();
                int PID = device.getProductId();
                String content = String.format("device name : %s, VID : %s, PID : %s", deviceName, VID, PID);
                LogCall.d(content);
                if (VID == 1155 && PID == 22352) {
                    LogCall.d("--->识别到H10B");
                    usbDevice = device;
                    getDeviceInterface(context, device);
                }
            }
        } else {
            LogCall.d("未找到设备");
        }
        LogCall.d("初始化结束");
    }

    private void getDeviceInterface(Context context, @NonNull UsbDevice usbDevice) {
        LogCall.d("获取device interface");
        int count = usbDevice.getInterfaceCount();
        for (int i = 0; i < count; i++) {
            UsbInterface usbInterface = usbDevice.getInterface(i);
            if (usbInterface.getInterfaceClass() == 3 && usbInterface.getInterfaceSubclass() == 0 && usbInterface.getInterfaceProtocol() == 0) {
                this.usbInterface = usbInterface;
                openDevice(context, usbInterface);
                break;
            }
        }
    }

    private void openDevice(Context context, @NonNull UsbInterface usbInterface) {
        LogCall.d("打开设备");
        UsbDeviceConnection conn = null;

        if (!usbManager.hasPermission(usbDevice)) {
            LogCall.d("没有权限, 请在弹窗中允许使用USB设备");
            PendingIntent pi = PendingIntent.getBroadcast(context, 0, new Intent(ACTION_USB_PERMISSION), 0);
            usbManager.requestPermission(usbDevice, pi);
            return;
        }
        if (usbManager.hasPermission(usbDevice)) {
            LogCall.d("有权限");
            conn = usbManager.openDevice(usbDevice);
        } else {
            LogCall.d("没有权限-2");
        }
        if (conn == null) {
            LogCall.d("conn == null");
            return;
        }
        if (conn.claimInterface(usbInterface, true)) {
            LogCall.d("conn.claimInterface = ture");
            deviceConnection = conn;
            assignEndpoint(usbInterface);
        } else {
            conn.close();
        }
        LogCall.d("打开设备-结束");
    }

    private void assignEndpoint(@NonNull UsbInterface usbInterface) {
        LogCall.d("设置endpoint");

        for (int i = 0; i < usbInterface.getEndpointCount(); i++) {
            UsbEndpoint ep = usbInterface.getEndpoint(i);
            if (ep.getType() == UsbConstants.USB_ENDPOINT_XFER_BULK) {
                if (ep.getDirection() == UsbConstants.USB_DIR_IN) {
                    usbEpIn = ep;
                } else {
                    usbEpOut = ep;
                }
            }
            if (ep.getType() == UsbConstants.USB_ENDPOINT_XFER_INT) {
                if (ep.getDirection() == UsbConstants.USB_DIR_IN) {
                    usbEpIn = ep;
                } else {
                    usbEpOut = ep;
                }
            }
        }

        if (usbEpIn != null) {
            //初始化H10B
            int send_result = h10b_start();
            if (send_result > 0) {
                startReading();
            }
        }
        LogCall.d("设置endpoint-结束");
    }


    public void startReading() {
        LogCall.d("开始读取数据");
        deviceConnection.claimInterface(usbInterface, true);
        isReading = true;
        Thread thread = new Thread(readRunnable);
        thread.start();
    }

    public void stopReading() {
        LogCall.d("停止读取数据");
        isReading = false;
    }


    /**
     * 数据发送方法，尽量在非主线程中进行
     *
     * @param data
     * @param dataLength
     */
    public int writeData(byte[] data, int dataLength) {
        synchronized (outLock) {
            if (deviceConnection != null && usbEpOut != null) {
                int writeResult = deviceConnection.bulkTransfer(usbEpOut, data, dataLength, 1000);
                if (writeResult >= 0) {
                    LogCall.d("发送成功 : " + writeResult);
                } else {
                    LogCall.d("发送失败 : " + writeResult);
                }
                return writeResult;
            } else {
                return -99;
            }
        }
    }

    //启动h10b
    public int h10b_start() {
        byte[] send = h10b_start_com();
        int send_result = writeData(send, send.length);
        LogCall.d("start result : " + send_result);
        return send_result;
    }

    private byte[] h10b_start_com() {
        //发送H10B启动命令
        byte[] send_start = new byte[12];
        send_start[0] = (byte) 0x48;//H
        send_start[1] = (byte) 0x31;//1
        send_start[2] = (byte) 0x30;//0
        send_start[3] = (byte) 0x42;//B
        send_start[4] = (byte) 0x3A;//:
        send_start[5] = (byte) 0x43;//C
        send_start[6] = (byte) 0x4F;//O
        send_start[7] = (byte) 0x4E;//N
        send_start[8] = (byte) 0x4E;//N
        send_start[9] = (byte) 0x45;//E
        send_start[10] = (byte) 0x43;//C
        send_start[11] = (byte) 0x54;//T
        return send_start;
    }

    //断开h10b
    public void h10b_stop() {
        byte[] send = h10b_stop_com();
        int send_result = writeData(send, send.length);
        LogCall.d("stop result : " + send_result);
    }

    private byte[] h10b_stop_com() {
        //发送H10B启动命令
        byte[] send_stop = new byte[15];
        send_stop[0] = (byte) 0x48;//H
        send_stop[1] = (byte) 0x31;//1
        send_stop[2] = (byte) 0x30;//0
        send_stop[3] = (byte) 0x42;//B
        send_stop[4] = (byte) 0x3A;//:
        send_stop[5] = (byte) 0x44;//D
        send_stop[6] = (byte) 0x49;//I
        send_stop[7] = (byte) 0x53;//S
        send_stop[8] = (byte) 0x43;//C
        send_stop[9] = (byte) 0x4F;//O
        send_stop[10] = (byte) 0x4E;//N
        send_stop[11] = (byte) 0x4E;//N
        send_stop[12] = (byte) 0x45;//E
        send_stop[13] = (byte) 0x43;//C
        send_stop[14] = (byte) 0x54;//T

        return send_stop;
    }


}
